﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Analyst3D;
using ESRI.ArcGIS.Display;
using System.Runtime.InteropServices;
using System.Collections;
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.Geometry;

namespace SPAS
{
    #region 柳伟佳、汤焱编写
    public partial class ShadowSimForm : Form
    {
        public IMapControl3 mapcontrol;
        private ShadowSimulation sim;
        public int currentCount = 0;

        public ShadowSimForm()
        {
            InitializeComponent();
        }

        private void ShadowSimForm_Load(object sender, EventArgs e)
        {
            this.MouseWheel += ShadowSimForm_MouseWheel;
            var layerCount = mapcontrol.LayerCount;
            for (int i = 0; i < layerCount; i++)
            {
                cmbBuilding.Items.Add(mapcontrol.get_Layer(i).Name);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            IFeatureLayer layer = axSceneControl1.Scene.get_Layer(0) as IFeatureLayer;
            IFeatureClass multi = layer.FeatureClass;

            string tempFilePath = Utils.GetTempFilePath();
            tempFilePath = System.IO.Path.ChangeExtension(tempFilePath, ".tif");

            IRaster raster = Utils.ConvertMultiPatchToRaster(multi, tempFilePath, double.Parse(txtPixelSize.Text));
            //ShadowSimulation sim = new ShadowSimulation(raster, dtStart.Value, dtEnd.Value, double.Parse(txtDeltaTime.Text), double.Parse(txtLat.Text), double.Parse(txtLon.Text));
            sim = new ShadowSimulation(raster, dtStart.Value, dtEnd.Value, double.Parse(txtDeltaTime.Text), double.Parse(txtLat.Text), double.Parse(txtLon.Text));

            sim.Simulate();

            currentCount = 0;
            timer1.Enabled = true;
            timer1.Interval = (int)(1000 / fpsSetting.Value);
            timer1.Start();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            currentCount += 1;
            if (currentCount > sim.RasterCount)
            {
                if ((currentCount - 1) % sim.RasterCount == 0)
                    axSceneControl1.Scene.get_Layer(sim.RasterCount).Visible = false;
                else
                    axSceneControl1.Scene.get_Layer((currentCount - 1) % sim.RasterCount).Visible = false;
                //var layer = axSceneControl1.Scene.get_Layer(currentCount % sim.RasterCount);
                if (currentCount % sim.RasterCount == 0)
                    axSceneControl1.Scene.get_Layer(sim.RasterCount).Visible = true;
                else
                    axSceneControl1.Scene.get_Layer(currentCount % sim.RasterCount).Visible = true;
                for (int i = 0; i < sim.RasterCount; i++)
                {
                    var layer = axSceneControl1.Scene.get_Layer(i + 1);
                }
                axSceneControl1.Update();
                axSceneControl1.Refresh();
            }
            else
            {
                IRasterLayer rasterLayer = new RasterLayerClass();
                rasterLayer.CreateFromRaster(sim.OutputRasters[currentCount - 1] as IRaster);
                rasterLayer.Name = currentCount.ToString();
                if (currentCount > 1)
                    axSceneControl1.Scene.get_Layer(currentCount - 1).Visible = false;
                axSceneControl1.Scene.AddLayer((ILayer)rasterLayer);
                axSceneControl1.Update();
                //axSceneControl1.SceneGraph.ActiveViewer.Redraw(true);
            }
            simTime.Text = dtStart.Value.AddMinutes((currentCount - 1) % sim.RasterCount * double.Parse(txtDeltaTime.Text)).ToLongTimeString();
        }


        private void UniqueValueRenderer(IFeatureLayer pFeatureLayer, string fieldName)
        {
            IGeoFeatureLayer pGeoFeatureLayer = pFeatureLayer as IGeoFeatureLayer;
            ITable pTable = pFeatureLayer as ITable;
            int fieldNumber = pTable.FindField(fieldName);
            IUniqueValueRenderer pUniqueRenderer = new UniqueValueRendererClass();
            pUniqueRenderer.FieldCount = 1;
            pUniqueRenderer.set_Field(0, fieldName);

            //设置显示颜色的范围
            IRandomColorRamp pRandColorRamp = new RandomColorRampClass();
            pRandColorRamp.StartHue = 0;
            pRandColorRamp.MinValue = 85;
            pRandColorRamp.MinSaturation = 15;
            pRandColorRamp.EndHue = 360;
            pRandColorRamp.MaxValue = 100;
            pRandColorRamp.MaxSaturation = 30;

            //创建随机颜色带
            pRandColorRamp.Size = getUniqueValue(pFeatureLayer.FeatureClass, fieldName).Count;
            bool bSucess = false;
            pRandColorRamp.CreateRamp(out bSucess);

            IEnumColors pEnumColors = pRandColorRamp.Colors;
            IColor pNextUniqueColor = null;

            //属性唯一值
            IQueryFilter pQueryFilter = new QueryFilterClass();
            pQueryFilter.AddField(fieldName);
            ICursor pCursor = pFeatureLayer.FeatureClass.Search(pQueryFilter, false) as ICursor;
            IRow pNextRow = pCursor.NextRow();
            object codeValue = null;
            IRowBuffer pNextRowBuffer = null;

            ISimpleFillSymbol pFillSymbol = null;

            while (pNextRow != null)
            {
                pNextRowBuffer = pNextRow as IRowBuffer;
                codeValue = pNextRowBuffer.get_Value(fieldNumber);
                pNextUniqueColor = pEnumColors.Next();
                if (pNextUniqueColor == null)
                {
                    pEnumColors.Reset();
                    pNextUniqueColor = pEnumColors.Next();
                }
                switch (pGeoFeatureLayer.FeatureClass.ShapeType)
                {
                    case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryMultiPatch:
                        pFillSymbol = new SimpleFillSymbolClass();
                        pFillSymbol.Color = pNextUniqueColor;
                        pFillSymbol.Style = esriSimpleFillStyle.esriSFSSolid;
                        Console.WriteLine(codeValue);
                        pUniqueRenderer.AddValue(codeValue.ToString(), "", pFillSymbol as ISymbol);
                        pUniqueRenderer.set_Symbol(codeValue.ToString(), pFillSymbol as ISymbol);
                        pNextRow = pCursor.NextRow();

                        break;

                    default:
                        pNextRow = pCursor.NextRow();
                        break;
                }
            }

            pFillSymbol = new SimpleFillSymbolClass();
            var pColor = new RgbColorClass();
            pColor.Transparency = 0;
            pFillSymbol.Color = pColor;
            pUniqueRenderer.set_Symbol("0", pFillSymbol as ISymbol);

            pGeoFeatureLayer.Renderer = pUniqueRenderer as IFeatureRenderer;

            //必须手动清除COM对象，否则会造成内存溢出（尤其是IQueryFilter,ICursor）
            Marshal.ReleaseComObject(pQueryFilter);
            Marshal.ReleaseComObject(pCursor);
            Marshal.ReleaseComObject(pEnumColors);
        }

        /// <summary>
        /// 查找某一属性的唯一值，返回属性唯一值的列表
        /// </summary>
        /// <param name="pFeatureClass">待查找的FeatureClass</param>
        /// <param name="field">待查找唯一值的字段</param>
        /// <returns>返回字段唯一值字符串的唯一值列表</returns>
        public static List<object> getUniqueValue(IFeatureClass pFeatureClass, string field)
        {
            string s = pFeatureClass.AliasName;
            List<object> uniqueValue = new List<object>();
            IFeatureCursor pCursor = pFeatureClass.Search(null, false);
            IDataStatistics pDataStat = new DataStatisticsClass();
            pDataStat.Field = field;
            pDataStat.Cursor = pCursor as ICursor;
            IEnumerator pEnumerator = pDataStat.UniqueValues;
            pEnumerator.Reset();
            while (pEnumerator.MoveNext())
            {
                uniqueValue.Add(pEnumerator.Current.ToString());
            }
            return uniqueValue;
        }

        private void cmbBuilding_SelectedIndexChanged(object sender, EventArgs e)
        {
            axSceneControl1.Scene.ClearLayers();
            var layer = mapcontrol.get_Layer(cmbBuilding.SelectedIndex);

            try
            {
                UniqueValueRenderer(layer as IFeatureLayer, "Height");
                axSceneControl1.Scene.AddLayer(layer);
                axSceneControl1.SceneGraph.Invalidate(layer, true, false);
                axSceneControl1.SceneGraph.ActiveViewer.Redraw(true);
                axSceneControl1.SceneGraph.RefreshViewers();
                axSceneControl1.Update();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                MessageBox.Show("请选择三维模型图层");
            }

        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (timer1.Enabled)
            {
                timer1.Enabled = false;
                button2.Text = "播放";
            }
            else
            {
                timer1.Enabled = true;
                button2.Text = "暂停";
            }

        }

        private void fpsSetting_ValueChanged(object sender, EventArgs e)
        {
            timer1.Interval = (int)(1000 / fpsSetting.Value);
        }


        private void ShadowSimForm_MouseWheel(object sender, MouseEventArgs e)
        {
            try
            {
                System.Drawing.Point pSceLoc = axSceneControl1.PointToScreen(this.axSceneControl1.Location);
                System.Drawing.Point Pt = this.PointToScreen(e.Location);
                if (Pt.X < pSceLoc.X | Pt.X > pSceLoc.X + axSceneControl1.Width | Pt.Y <
                    pSceLoc.Y | Pt.Y > pSceLoc.Y + axSceneControl1.Height) return;
                double scale = 0.2;
                //if (e.Delta < 0) scale = -0.2;
                if (e.Delta > 0) scale = -0.2;
                ICamera pCamera = axSceneControl1.Camera;
                IPoint pPtObs = pCamera.Observer;
                IPoint pPtTar = pCamera.Target;
                pPtObs.X += (pPtObs.X - pPtTar.X) * scale;
                pPtObs.Y += (pPtObs.Y - pPtTar.Y) * scale;
                pPtObs.Z += (pPtObs.Z - pPtTar.Z) * scale;
                pCamera.Observer = pPtObs;
                axSceneControl1.SceneGraph.RefreshViewers();
            }
            catch
            {
            }
        }

    }
    #endregion
}